/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <uk/test.h>
#include <uk/intctlr.h>
#include <uk/plat/lcpu.h>

static struct uk_intctlr_desc *ori_intctlr;
static struct uk_intctlr_desc test_intctlr;
struct uk_intctlr_driver_ops test_ops;
static int ret;

enum ukintctlr_test_ret {
	TEST_DEFAULT,
	TEST_CONFIGURE_IRQ_SUCCESS,
	TEST_FDT_XLAT_SUCCESS,
	TEST_MASK_IRQ_SUCCESS,
	TEST_UNMASK_IRQ_SUCCESS,
	TEST_INITIALIZE_SUCCESS,
	TEST_HANDLE_SUCCESS,
	TEST_SGI_OP_SUCCESS,
	TEST_PERCPU_INIT_SUCCESS,
};

static int test_configure_irq(struct uk_intctlr_irq *irq)
{
	(void)*irq;
	ret = TEST_CONFIGURE_IRQ_SUCCESS;
	return 0;
}

static int test_fdt_xlat(const void *fdt __unused, int nodeoffset, __u32 index,
			 struct uk_intctlr_irq *irq)
{
	(void)nodeoffset;
	(void)index;
	(void)*irq;
	ret = TEST_FDT_XLAT_SUCCESS;
	return 0;
}

static void test_mask_irq(unsigned int irq)
{
	(void)irq;
	ret = TEST_MASK_IRQ_SUCCESS;
}

static void test_unmask_irq(unsigned int irq)
{
	(void)irq;
	ret = TEST_UNMASK_IRQ_SUCCESS;
}

static void test_handle(struct __regs *regs)
{
	(void)*regs;
	ret = TEST_HANDLE_SUCCESS;
}

static void test_sgi_op(uint8_t sgintid, uint32_t cpuid)
{
	(void)sgintid;
	(void)cpuid;
	ret = TEST_SGI_OP_SUCCESS;
}

static int test_percpu_init(uint64_t cpuid)
{
	(void)cpuid;
	ret = TEST_PERCPU_INIT_SUCCESS;

	return 0;
}

static inline void test_intctlr_init(void)
{
	ori_intctlr = uk_intctlr;
	ret = 0;

	test_intctlr.name = "TEST_INTCTLR";
	test_ops.configure_irq = test_configure_irq;
	test_ops.fdt_xlat = test_fdt_xlat;
	test_ops.mask_irq = test_mask_irq;
	test_ops.unmask_irq = test_unmask_irq;
	test_ops.handle = test_handle;
	test_ops.sgi_op = test_sgi_op;
	test_ops.percpu_init = test_percpu_init;
	test_intctlr.ops = &test_ops;

	uk_intctlr_register(&test_intctlr);
}

/* 测试configure_irq接口 */
UK_TESTCASE(ukintctlr, call_intctlr_configure_irq)
{
	struct uk_intctlr_irq irq = {0};
	struct uk_intctlr_irq *p_irq = &irq;

	/* 1.备份原有uk_intctlr，初始化测试环境 */
	test_intctlr_init();

	/* 2.通过统一接口调用configure_irq，并校验调用结果 */
	(void)uk_intctlr_irq_configure(p_irq);
	UK_TEST_EXPECT_SNUM_EQ(ret, TEST_CONFIGURE_IRQ_SUCCESS);

	/* 3.恢复环境 */
	uk_intctlr_register(ori_intctlr);
}

/* 测试fdt_xlat接口 */
UK_TESTCASE(ukintctlr, call_fdt_xlat)
{
	struct uk_intctlr_irq irq = {0};
	struct uk_intctlr_irq *p_irq = &irq;
	const char *fdt = "FDT";
	int nodeoffset = 0;
	__u32 index = 0;

	/* 1.备份原有uk_intctlr，初始化测试环境 */
	test_intctlr_init();

	/* 2.通过统一接口调用fdt_xlat，并校验调用结果 */
	(void)uk_intctlr_irq_fdt_xlat(fdt, nodeoffset, index, p_irq);
	UK_TEST_EXPECT_SNUM_EQ(ret, TEST_FDT_XLAT_SUCCESS);

	/* 3.恢复环境 */
	uk_intctlr_register(ori_intctlr);
}

/* 测试mask_irq接口 */
UK_TESTCASE(ukintctlr, call_mask_irq)
{
	int irq = 0;

	/* 1.备份原有uk_intctlr，初始化测试环境 */
	test_intctlr_init();

	/* 2.通过统一接口调用mask_irq，并校验调用结果 */
	uk_intctlr_irq_mask(irq);
	UK_TEST_EXPECT_SNUM_EQ(ret, TEST_MASK_IRQ_SUCCESS);

	/* 3.恢复环境 */
	uk_intctlr_register(ori_intctlr);
}

/* 测试unmask_irq接口 */
UK_TESTCASE(ukintctlr, call_unmask_irq)
{
	int irq = 0;

	/* 1.备份原有uk_intctlr，初始化测试环境 */
	test_intctlr_init();

	/* 2.通过统一接口调用unmask_irq，并校验调用结果 */
	uk_intctlr_irq_unmask(irq);
	UK_TEST_EXPECT_SNUM_EQ(ret, TEST_UNMASK_IRQ_SUCCESS);

	/* 3.恢复环境 */
	uk_intctlr_register(ori_intctlr);
}

/* 测试handle接口 */
UK_TESTCASE(ukintctlr, call_handler)
{
	struct __regs *regs = NULL;

	/* 1.备份原有uk_intctlr，初始化测试环境 */
	test_intctlr_init();

	/* 2.通过统一接口调用handle，并校验调用结果 */
	uk_intctlr_handle(regs);
	UK_TEST_EXPECT_SNUM_EQ(ret, TEST_HANDLE_SUCCESS);

	/* 3.恢复环境 */
	uk_intctlr_register(ori_intctlr);
}

/* 测试sgi_op接口 */
UK_TESTCASE(ukintctlr, call_sgi_op)
{
	uint8_t sgintid = 0;
	uint32_t cpuid = 0;

	/* 1.备份原有uk_intctlr，初始化测试环境 */
	test_intctlr_init();

	/* 2.通过统一接口调用sgi_op，并校验调用结果 */
	(void)uk_intctlr_sgi_op(sgintid, cpuid);
	UK_TEST_EXPECT_SNUM_EQ(ret, TEST_SGI_OP_SUCCESS);

	/* 3.恢复环境 */
	uk_intctlr_register(ori_intctlr);
}

/* 测试percpu_init接口 */
UK_TESTCASE(ukintctlr, call_percpu_init)
{
	uint64_t sgintid = 0;
	int r;

	/* 1.备份原有uk_intctlr，初始化测试环境 */
	test_intctlr_init();

	/* 2.通过统一接口调用percpu_init，并校验调用结果 */
	r = uk_intctlr_percpu_init(sgintid);
	UK_TEST_EXPECT_SNUM_EQ(ret, TEST_PERCPU_INIT_SUCCESS);
	UK_TEST_EXPECT_ZERO(r);

	/* 3.恢复环境 */
	uk_intctlr_register(ori_intctlr);
}

uk_testsuite_register(ukintctlr, NULL);
